/************************************************************************
 * FilePath: /src/dict_server.c
 * 创 建 人: George Gao
 * Gitee: https://gitee.com/EmbeddedGeorge/Online_Dictionary
 * 创建日期: 2020年02月27日 16:18:34
 * 文件描述: 
 * 版 本 号: 1.0
 * 修改日期: 2020年02月28日 17:55:55
 * 修改记录: 初建
 * *********************************************************************/

#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sqlite3.h>
#include <signal.h>

#include <sys/stat.h>
#include <fcntl.h>

#include <time.h>

#define Register  1
#define Login     2
#define Query     3
#define History   4

#define DATABASE  "userinfo.db"

//定义通信双方的信息结构体
typedef struct 
{
    int type;
    char name[32];
    char data[256];
}MSG;

int do_client(int acceptfd, sqlite3 *db);
int do_register(int acceptfd, MSG *msg, sqlite3 *db);
int do_login(int acceptfd, MSG *msg, sqlite3 *db);
int do_query(int acceptfd, MSG *msg, sqlite3 *db);
int do_history(int acceptfd, MSG *msg, sqlite3 *db);
int do_history_2(int acceptfd, MSG *msg, sqlite3 *db);

// ./server 192.168.11.192 10000
int main(int argc, char *argv[])
{
    int sockfd;
    struct sockaddr_in serveraddr;
    int cmd;
    MSG msg;
    sqlite3 *db;
    int acceptfd;
    pid_t pid;
    char cmdbuf[128] = {};  //存放数据库命令
    char *errmsg;  //记录数据库的出错信息
    if(argc != 3){
        printf("Usage:%s serverip port.\r\n", argv[0]);
        return -1;
    }

    //打开数据库
    if((sqlite3_open(DATABASE, &db)) != SQLITE_OK){
        printf("%s\r\n", sqlite3_errmsg(db));
        exit(-1);
    }
    printf("Open database success\r\n");
    
    //创建一张数据库的用户表, 其中 name 设置为主键<不允许记录中有相同的 name >
    sprintf(cmdbuf, "create table  if not exists user(id Integer UNIQUE, name text primary key, password text);");
    if((sqlite3_exec(db, cmdbuf, NULL, NULL, &errmsg)) != SQLITE_OK){
        printf("%s\n", errmsg);
        exit(-1);
    }
    //创建一张数据库的历史记录表 >
    sprintf(cmdbuf, "create table  if not exists record(name text, date text, word text);");
    if((sqlite3_exec(db, cmdbuf, NULL, NULL, &errmsg)) != SQLITE_OK){
        printf("%s\n", errmsg);
        exit(-1);
    }
    printf("create table or open success.\r\n");
    
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
        perror("socket error\r\n");
        exit(-1);
    }
    
    bzero(&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = INADDR_ANY;
    serveraddr.sin_port = htons(atoi(argv[2]));

    if((bind(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr))) < 0){
        perror("bind error\r\n");
        close(sockfd);
        exit(-1);
    }

    //将套接字设为监听模式
    if((listen(sockfd, 5)) < 0){
        perror("listen error\r\n");
        close(sockfd);
        exit(-1);
    }
    
    signal(SIGCHLD, SIG_IGN);  //处理僵尸进程

    while(1)
    {
        if((acceptfd = accept(sockfd, NULL, NULL)) < 0){
            perror("accept error\r\n");
            close(sockfd);
            exit(-1);
        }

        if((pid = fork()) < 0){
            perror("fork error\r\n");
            exit(-1);
        }
        else if(pid == 0){
            //子进程 处理客户端的具体消息
            close(sockfd);
            do_client(acceptfd, db);
        }
        else{
            //父进程 接收客户端的请求
            close(acceptfd);
        }
    }

    return 0;
}

int do_client(int acceptfd, sqlite3 *db)
{
    MSG msg;
    while((recv(acceptfd, &msg, sizeof(msg), 0)) > 0)
    {
        printf("type:%d\r\n", msg.type);
        switch(msg.type)
        {
            case Register:do_register(acceptfd, &msg, db);break;
            case Login:do_login(acceptfd, &msg, db);break;
            case Query:do_query(acceptfd, &msg, db);break;
            case History:do_history_2(acceptfd, &msg, db);break;
            default:printf("Invalid data msg!\r\n");break;
        }
    }
    printf("client exit!\r\n");
    close(acceptfd);
    
    return 0;
}

int do_register(int acceptfd, MSG *msg, sqlite3 *db)
{
    char cmdbuf[128] = {};
    char *errmsg;
    int id = 1;
    
    sprintf(cmdbuf, "insert into user values(%d, '%s', '%s');", id, msg->name, msg->data);
    printf("cmdbuf:%s\r\n", cmdbuf);
    if((sqlite3_exec(db, cmdbuf, NULL, NULL, &errmsg)) != SQLITE_OK){
        printf("%s\r\n", errmsg);
        strcpy(msg->data, "user name already exist!");
    }
    else{
        printf("Client register ok!\r\n");
        strcpy(msg->data, "ok!");
    }
    
    if((send(acceptfd, msg, sizeof(MSG), 0)) < 0)
    {
        perror("send error\r\n");
        return -1;
    }

    return 0;
}

int do_login(int acceptfd, MSG *msg, sqlite3 *db)
{
    char cmdbuf[128] = {};
    char *errmsg;
    int nrow, ncloumn;
    char **resultp;
    
    sprintf(cmdbuf, "select * from user where name = '%s' and password = '%s';", msg->name, msg->data);
    printf("cmdbuf:%s\r\n", cmdbuf);
    if((sqlite3_get_table(db, cmdbuf, &resultp, &nrow, &ncloumn, &errmsg)) != SQLITE_OK){
        printf("%s\r\n", errmsg);
        return -1;
    }
    else{
        printf("Query user success!\r\n");
    }
    //查询成功，数据库中拥有此用户
    if(nrow == 1){
        strcpy(msg->data, "OK");
    }
    else{  //用户名或密码错误
        strcpy(msg->data, "username or password wrong!");
    }
    
    if((send(acceptfd, msg, sizeof(MSG), 0)) < 0)
    {
        perror("send error\r\n");
        return -1;
    }

    return 0;
}

int do_searchword(MSG *msg)
{
    FILE *fp;
    char temp[512];
    int len;
    int result;
    char *p;

    //打开单词信息文件
    fp = fopen("dict.txt", "r");
    if(fp == NULL){
        printf("Open error!\r\n");
        return -1;
    }
    
    //打印出，客户端要查询的单词
    len = strlen(msg->data);
    printf("%s, len = %d\r\n", msg->data, len);
    while(fgets(temp, 512, fp) != NULL)
    {
        result = strncmp(msg->data, temp, len);
        if(result > 0){ // <word
            continue;
        }
        else if(result < 0){ // > word
            printf("no word\r\n");
            break;
        }

        if(temp[len] != ' '){
            continue;
        }
        // 找到单词，分离空格
        p = temp + len;
        while(*p == ' ')
        {
            p++;
        }
        //拷贝分离空格后的注释
        strcpy(msg->data, p);
        fclose(fp);
        return 1;
    }

    fclose(fp);
    return 0;
}

int get_date(char *date)
{
    time_t t;
    struct tm *tp;

    time(&t);
    //时间格式转换
    tp = localtime(&t);
    sprintf(date, "%d-%d-%d %d:%d;%d", tp->tm_year+1900, tp->tm_mon+1, tp->tm_mday, 
                                        tp->tm_hour, tp->tm_min, tp->tm_sec);
    return 0;
}

int do_query(int acceptfd, MSG *msg, sqlite3 *db)
{
    char word[32];
    int ret = 0;
    char date[64];
    char cmdbuf[128];
    char *errmsg;
    
    strcpy(word, msg->data);  //取出要查询的单词

    ret = do_searchword(msg);

    //表示找到单词，将用户名，时间，单词放入历史记录表
    if(ret == 1){
        //获取系统时间
        get_date(date);
        sprintf(cmdbuf, "insert into record values('%s', '%s', '%s');", msg->name, date, word);
        printf("cmdbuf:%s\r\n", cmdbuf);
        if((sqlite3_exec(db, cmdbuf, NULL, NULL, &errmsg)) != SQLITE_OK){
            printf("%s\r\n", errmsg);
        }
        else{
            printf("Insert record ok!\r\n");
        }
    }
    else if(ret == -1){
        strcpy(msg->data, "Dict open faild!");
    }
    else{  //没有找到该单词
        printf("No word\r\n");
        strcpy(msg->data, "Don't find this word!");
    }

    //将查询结果，发送给客户端
    if((send(acceptfd, msg, sizeof(MSG), 0)) < 0)
    {
        perror("send error\r\n");
        return -1;
    }

    return 0;
}

int do_history(int acceptfd, MSG *msg, sqlite3 *db)
{
    char cmdbuf[128] = {};
    char *errmsg;
    int nRow, nColumn;
    char **resultp;
    char temp[512];
    
    sprintf(cmdbuf, "select * from record where name = '%s';", msg->name);
    printf("cmdbuf:%s\r\n", cmdbuf);
    if((sqlite3_get_table(db, cmdbuf, &resultp, &nRow, &nColumn, &errmsg)) != SQLITE_OK){
        printf("%s\r\n", errmsg);
        return -1;
    }

    int index = 0, i, j;
    for(i=0;i<=nRow; i++)
    {
        for(j=0; j<nColumn; j++)
        {
            strcat(temp, resultp[index++]);
            if(j == (nColumn-1)){
                strcat(temp, "\n");
            }
            else{
                strcat(temp, "  ");
            }
        }
    }
    printf("Query history done.\r\n");

    strcpy(msg->data, temp);
    //将查询的历史记录，发送给客户端
    if((send(acceptfd, msg, sizeof(MSG), 0)) < 0)
    {
        perror("send error\r\n");
        return -1;
    }
    return 0;
}

//得到查询结果，并需要将历史记录发送给客户端
int history_callback(void *para, int f_num, char **f_value, char **f_name)
{
    // record: name, date, word
    int acceptfd;
    acceptfd = *((int *)para);
    MSG msg;
    
    sprintf(msg.data, "%s , %s", f_value[1], f_value[2]);
    
    if((send(acceptfd, &msg, sizeof(MSG), 0)) < 0)
    {
        perror("send error\r\n");
        return -1;
    }
    
    return 0;
}
int do_history_2(int acceptfd, MSG *msg, sqlite3 *db)
{
    char cmdbuf[128] = {};
    char *errmsg;
    char temp[512];
    
    sprintf(cmdbuf, "select * from record where name = '%s';", msg->name);
    printf("cmdbuf:%s\r\n", cmdbuf);
    if((sqlite3_exec(db, cmdbuf, history_callback,(void *)&acceptfd, &errmsg)) != SQLITE_OK){
        printf("%s\r\n", errmsg);
        return -1;
    }
    printf("Query history done.\r\n");

    return 0;
}

/***************************** End Of File *****************************/
